<template>
  <div>

    <!-- 用于视口：超出部分滚动 -->
    <div class="viewport" ref="viewport" :style="{'--rowheight': state.rowHeight + 'px'}" @scroll="onScroll">
      <div class="scrollbar" ref="scrollbar"></div>
      <!-- 子元素超出父元素高度 -->
      <div class="list" ref="listref">
        <div class="row" v-for="(item, i) in showList" :key="i">
          {{item.n}}
        </div>
      </div>
    </div>
  </div>
</template>

<script lang="ts">
import { computed, defineComponent, onMounted, reactive, ref } from 'vue'

export default defineComponent({
  setup() {
    let list = new Array(200000).fill(null).map((ele, i) => ({n:i+1}));
    const viewport: any = ref(null);
    const scrollbar: any = ref(null);
    const listref: any = ref(null);
    let state = reactive({
      start: 0,
      end: 20,
      viewCount: 20, // 显示多少数据
      rowHeight: 20, // 行高
    })
    onMounted(() => {
      viewport.value.style.height = (state.rowHeight * state.viewCount) + 'px';
      scrollbar.value.style.height = (state.rowHeight * list.length) + 'px';
    })
    const showList = computed(() => {
      return list.slice(state.start, state.end);
    })
    const onScroll = () => {
      let  offsetTop = viewport.value.scrollTop;
      state.start = Math.round(offsetTop/state.rowHeight);
      state.end = state.start + state.viewCount;
      console.log(state.start, state.end)
      listref.value.style.transform = `translateY(${offsetTop}px)`;
    }
    return {
      onScroll,
      listref,
      showList,
      viewport,
      scrollbar,
      state
    }
  },
})
</script>

<style lang="scss" scoped>
.viewport{
  // height: 400px;
  width: 300px;
  background-color: yellowgreen;
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  margin: auto;
  overflow-y: scroll;
  .scrollbar{
    // height: 3000px;
  }
  .list{
    position: absolute;
    left: 0;
    top: 0;
    .row{
      // height: 20px;
      height: var(--rowheight);
    }
  }
}
</style>

